# -*- coding:utf-8 -*-

# realize  motionmodel functions

from builtins import range
from functools import reduce
import numpy as np
from ctypes import *
from cmsg import *
from satProp import *
import logging 
'''
    Some common keys of state
    expect  : expectation
    cov     :  cov

    noiseE  : expectation of noise
    noiseCov: cov of noise
'''

class motionModel(object):
    '''
        base class of motion model
    '''
    def __init__(self, args=None):
        if args is None:
            args = dict({})
        self.args = args
    
    def updatePara(self,args):
        self.args.update(args)

    def transform(self, priorMsg=None):
        '''
            trans form with particle mode
        '''
        pass
    def variantionalTransform(self, priorMsg=None):
        '''
            transform with variational form
        '''
        pass

class randomWalkMotion(motionModel):
    '''
        random walk motion model
        X[n-1] =   X[n] + w[n], w[n] is Guassian Model
    '''
    def transform(self,priorMsg=None):
        '''
            transform msg in to another message
            TODO it just supports guassian model message
        '''
        assert isinstance(priorMsg,normalDistributeMsg),'not support yet'
        # logging.error(priorMsg.mean)
        expectNow = priorMsg.mean + self.args['noiseE']
        cov       = priorMsg.cov + self.args['noiseCov']
        msgOut = normalDistributeMsg('msgout',expectNow,cov)
        return msgOut

class satellitePropMotion(motionModel):
    '''
    satellite propagation model
    NOTE: the args MUST include the real world time (NOT satellite's reading time)
          'sat': cSat instance
          'startTime':
          'endTime': time, float
    '''
    
    def setForward(self,isforward=True):
        '''
            forward boolean makes startTime is the start Time 
        '''
        self.isforward = isforward 

    def transform(self,priorMsg=None):
        try:
            assert isinstance(priorMsg,normalDistributeMsg),'not support yet'
        except:
            print 'e'
        # sat = self.args['sat']
        logging.debug('Motion model says: i am propagation:------>')
        if self.isforward:
            logging.debug('Motion model forward :------>')
            startTime = self.args['startTime']
            endTime   = self.args['endTime']
        else:
            logging.debug('Motion model backward :------>')
            startTime = self.args['endTime']
            endTime   = self.args['startTime']
        
        logging.debug('start/end time: %f / %f' %(startTime,endTime))
       
        # transform the msg to outputdata Form 
        stateWrapper =  cStateWrapper(priorMsg.mean,priorMsg.cov) 
        logging.debug('input statement:'+stateWrapper.__str__() )
        inputFormState = stateWrapper.changeForm(np.zeros((3,1)))
        outputData   = IntergOutPut()
        inputData   = constructIntergInput(time2BDT(startTime),time2BDT(endTime),
                                            inputFormState[0],inputFormState[1])
        try:
            LOCK.aquire()
        except:
            pass
        LIB_ORBIT_PROP.Integrator_Module(byref(inputData),byref(outputData))
        
        try:
            LOCK.release()
        except:
            pass
        outputState = createStateWrapperFromPropOutPut(outputData)
        logging.debug('output statement:'+outputState.__str__() )
        logging.debug('Motionmodel : propagation complete:<-------')
        return outputState
class staticMotion(satellitePropMotion):
     def transform(self,priorMsg=None):
        stateWrapper =  cStateWrapper(priorMsg.mean,priorMsg.cov)
        return stateWrapper


if __name__ == '__main__':
    a= motionModel()
    b= motionModel() 
    args ={'a':1}
    a.updatePara(args)
    args ={'a':2}
    b.updatePara(args)